﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Collections.Specialized;
using DTC.Database;
using DTC.Popups;

namespace DTC
{
    /// <summary>
    /// Interaction logic for JournalChart.xaml
    /// </summary>
    public partial class JournalChart : UserControl
    {
        public JournalChart()
        {
            InitializeComponent();
            DateTime.TryParse("5:00", out hourFrom);
            DateTime.TryParse("23:00", out hourTo);
            SetGrid();
            newVisit = new NewVisitVisual();
            newVisit.Host = this;
            BChart.AddVisual(newVisit);    
        }

        #region PrivateProperies
        //data Collections
        private ObservableCollection<DTCDoctor> DoctorsProperty;
        //Visuals Holders
        private GridVisual grid;
        private ObservableCollection<DTCVisit> visits;
        private List<string> headerRowString;
        private DateTime hourFrom;
        private DateTime hourTo;
        private SelectionVisual selection;
        private NewVisitVisual newVisit;
        private TimeLabelVisual timeLabel;
        private bool visitFocused = false;
        private DTCPatient highlightPatient;

        private double cellWidth = 120;
        private double cellHeight = 21;
        #endregion

        #region PublicFields
        public ObservableCollection<DTCDoctor> Doctors
        {
            get
            {
                return DoctorsProperty;
            }
            set
            {
                DoctorsProperty = value;
                DoctorsProperty.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Doctors_CollectionChanged);
                HeaderColumn.ItemsSource = DoctorsProperty;
                SetGrid();
            }
        }
        public ObservableCollection<DTCVisit> Visits
        {
            get
            {
                return visits;
            }
            set
            {
                if (visits != value)
                {
                    if (BChart.Children.Count != 0)
                        BChart.Children.Clear();
                    visits = value;
                    SetVisits();
                }
            }
        }
        public DateTime HourFrom
        {
            get
            {
                return hourFrom;

            }
            set
            {
                if (hourFrom != value)
                {
                    hourFrom = value;
                    SetGrid();
                }
            }
        }
        public DateTime HourTo
        {
            get
            {
                return hourTo;

            }
            set
            {
                if (hourTo != value)
                {
                    hourTo = value;
                    SetGrid();
                }
            }
        }
        public double CellWidth
        {
            get
            {
                return cellWidth;
            }
            set
            {
                if (cellWidth != value)
                {
                    cellWidth = value;
                    grid.CellWidth = value;
                    //HeaderRow element width = value;
                    //invalidate somehoe
                }
            }
        }
        public double CellHeight
        {
            get
            {
                return cellHeight;
            }
            set
            {
                if (cellHeight != value)
                {
                    cellHeight = value;
                    grid.CellHeight = value;
                    //headerColumn element height = value
                    //invalidate somehow
                }
            }
        }
        public int RowCount
        {
            get
            {
                return DoctorsProperty.Count;
            }
        }
        public bool VisitFocused
        {
            get
            {
                return visitFocused;
            }
            set
            {
                if (visitFocused != value)
                {
                    visitFocused = value;
                    timeLabel.Visible = !visitFocused;

                }
            }
        }
        public DTCPatient HightlightedPatient
        {
            get
            {
                return highlightPatient;
            }
            set
            {
                if (highlightPatient != value)
                {
                    highlightPatient = value;
                    foreach (DTCVisit vis in visits)
                    {
                        if (vis.DTCPatient == highlightPatient)
                        {
                            vis.Visual.Background = new SolidColorBrush((Color)new ColorConverter().ConvertFrom("#FFD71A1A"));
                        }
                        else
                        {
                            vis.Visual.Background = new SolidColorBrush((Color) new ColorConverter().ConvertFrom("#FF4277DB"));
                        }
                    }
                }
            }
        }
        public DateTime Date
        {
            get
            {
                return hourFrom.Date;
            }
            set
            {
                if (hourFrom.Date != value.Date)
                {
                    DateTime tmp = hourFrom;
                    hourFrom = value.Date.AddHours(hourFrom.Hour).AddMinutes(hourFrom.Minute);
                }
            }
        }

        #endregion

        private void UserControl_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            //HeaderColumn.Height = grid.Height;
            if (headerRowString != null)
            {
                HeaderRow.Width = headerRowString.Count * cellWidth;
                grid.Width = HeaderRow.Width;
                selection.Width = grid.Width;
                BChart.Width = grid.Width;
            }
            BChart.Height = grid.Height;
            selection.Heigth = grid.Height;
            grid.SizeChanged(sender, e);
        }
        private void SetGrid()
        {
            if(grid == null)
                grid = new GridVisual();
            grid.CellHeight = CellHeight;
            grid.CellWidth = CellWidth;
            if (DoctorsProperty != null)
                grid.RowCount = DoctorsProperty.Count;
            SetHeaderRow();
            if(headerRowString != null)
                grid.ColumnCount = headerRowString.Count;
            if(!BChart.HasGrid)
                BChart.AddGrid(grid);
            if (selection == null)
                selection = new SelectionVisual();
            selection.Host = this;
            if(!BChart.HasSelection)
            BChart.AddSelection(selection);
            if (timeLabel == null)
                timeLabel = new TimeLabelVisual();
            timeLabel.Host = this;
            if (!BChart.HasTimeLable)
                BChart.AddTimeLable(timeLabel);
        }
        private void SetHeaderRow()
        {
            if (headerRowString == null)
                headerRowString = new List<string>();
            else headerRowString.Clear();
            int i = hourFrom.Hour+1;
            headerRowString.Add("");
            int bound = hourTo.Hour;
            while (i <= bound)
            {
                headerRowString.Add(i.ToString() + ":00");
                i++;
            }
            HeaderRow.ItemsSource = headerRowString;

        }
        private void SetVisits()
        {
            foreach (DTCVisit vis in visits)
            {
                VisitVisual tmp = new VisitVisual();
                tmp.Visit = vis;
                tmp.Host = this;
                BChart.AddVisit(tmp);
            }
        }
        private void ScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
        {
            if (e.VerticalOffset != 0)
                VerticalHeaderScroller.ScrollToVerticalOffset(e.VerticalOffset);
            else if (e.VerticalChange != 0)
                VerticalHeaderScroller.ScrollToVerticalOffset(e.VerticalChange);
            if (e.HorizontalOffset != 0)
                HorizontalHeaderScroller.ScrollToHorizontalOffset(e.HorizontalOffset);
            else if (e.HorizontalChange != 0)
                HorizontalHeaderScroller.ScrollToHorizontalOffset(e.HorizontalChange);
        }
        public double TimeToPos(DateTime time)
        {
            double t = ((time.Hour - hourFrom.Hour) * 3600) + ((time.Minute -hourFrom.Millisecond) * 60) + (time.Second -hourFrom.Second);
            return t*(CellWidth/3600);

        }
        public double DoctorToPos(DTCDoctor doc)
        {
            return (double)HeaderColumn.Items.IndexOf(doc);
        }
        public DateTime PosToTime(double x)
        {
            double offset = x /( cellWidth / 3600.0);
            return hourFrom.AddSeconds(offset);
        }
        public int PosToDoctorIndex(double y)
        {
            if (y > HeaderColumn.Items.Count * CellHeight)
                return HeaderColumn.Items.Count * (int)CellHeight;
            return (int)(y/CellHeight);
        }
        public double MinuteLength
        {
            get
            {
                return CellWidth / 60.0;
            }
        }

        private double GetNearestX(double x)
        {
            int cel = (int)(x / cellWidth);
            double celstart = (double)(cel) * cellWidth;
            double offset = x - celstart;
            int LeftOffsetNum = (int)(offset / (cellWidth / 12));
            int RightOffsetNum = (int)((offset + (cellWidth / 12)) / (cellWidth / 12));
            double ro = Math.Abs((RightOffsetNum * cellWidth / 12) - offset);
            double lo = Math.Abs((LeftOffsetNum * cellWidth / 12) - offset);
            double finalPoint;
            if (lo < ro)
                finalPoint = celstart + ((double)LeftOffsetNum * (cellWidth / 12));
            else
                finalPoint = celstart + ((double)RightOffsetNum * (cellWidth / 12));
            return finalPoint;
        }
        private double GetNearestY(double y)
        {
            return PosToDoctorIndex(y) * cellHeight;
        }


        private void BChart_MouseMove(object sender, MouseEventArgs e)
        {
            double nearestX = GetNearestX(e.GetPosition(BChart).X);
            if (newVisit.IsDrawing)
            {
                newVisit.EndsAt = nearestX;
            }
            else
            {
                selection.Position = timeLabel.Position  = nearestX;
                selection.SelectedRow = timeLabel.SelectedRow = PosToDoctorIndex(e.GetPosition(BChart).Y);
                selection.Render();
                HeaderColumn.SelectedIndex = selection.SelectedRow;
                timeLabel.Render();
                
            }
        }

        private void BChart_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            VisitPopup vp = new VisitPopup();
            vp.Owner = App.Current.MainWindow;
            vp.Visit.DateFrom = PosToTime(newVisit.StartPoint.X);
            vp.Visit.DateTo = PosToTime(newVisit.EndPoint.X);
            vp.SelectedDoctor = (DTCDoctor)HeaderColumn.Items[PosToDoctorIndex(newVisit.StartPoint.Y)];
            if (vp.ShowDialog() == true)
            {
                VisitVisual tmp = new VisitVisual();
                tmp.Visit = vp.Visit;
                tmp.Host = this;
                BChart.AddVisit(tmp);
            }
            newVisit.IsDrawing = false;
            selection.NoLabel = false;
        }

        private void BChart_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            selection.NoLabel = true;
            newVisit.StartPoint = new Point(GetNearestX(e.GetPosition(BChart).X), GetNearestY(e.GetPosition(BChart).Y));
        }
        private void Doctors_CollectionChanged( Object sender, NotifyCollectionChangedEventArgs e)
        {
            SetGrid();
            SetVisits();
            UserControl_SizeChanged(selection, null);
        }
    }

    #region Visuals
    public class GridVisual : DrawingVisual
    {
        private Thickness margin = new Thickness(0,0,0,0);
        private Brush background = Brushes.White;
        private Brush lineColor = Brushes.Gray;
        private Pen verticalLine = new Pen(Brushes.Gray, 1);
        private Pen horizontalLine = new Pen(Brushes.Gray, 1);
        private Pen horizontalSeparator;
        private double cellWidth = 120;
        private double cellHeight = 21;
        private int rowCount = 0;
        private int columnCount = 0;
        private double width=0;
        private double height=0;

        public Thickness Margin
        {
            get
            {
                return margin;
            }
            set
            {
                if (margin != value)
                    margin = value;
            }
        }
        public Brush Background
        {
            get
            {
                return background;
            }
            set
            {
                if (background != value)
                    background = value;
            }
        }
        public Brush LineColor
        {
            get
            {
                return lineColor;
            }
            set
            {
                if (lineColor != value)
                    lineColor = value;
            }
        }
        public Pen VerticalLine
        {
            get
            {
                return verticalLine;
            }
            set
            {
                if (verticalLine != value)
                    verticalLine = value;
            }
        }
        public Pen HorizontalLine
        {
            get
            {
                return horizontalLine;
            }
            set
            {
                if (horizontalLine != value)
                    horizontalLine = value;
            }
        }
        public Pen HorizontalSeparator
        {
            get
            {
                return horizontalSeparator;
            }
            set
            {
                if (horizontalSeparator != value)
                    horizontalSeparator = value;
            }
        }
        public double CellWidth
        {
            get
            {
                return cellWidth;
            }
            set
            {
                if (cellWidth != value)
                    cellWidth = value;
            }
        }
        public double CellHeight
        {
            get
            {
                return cellHeight;
            }
            set
            {
                if (cellHeight != value)
                    cellHeight = value;
            }
        }
        public int RowCount
        {
            get
            {
                return rowCount;
            }
            set
            {
                if (rowCount != value)
                    rowCount = value;
            }
        }
        public int ColumnCount
        {
            get
            {
                return columnCount;
            }
            set
            {
                if (columnCount != value)
                    columnCount = value;
            }
        }
        public double Width
        {
            get
            {
                if(width ==0)
                    width = cellWidth * columnCount;
                return width;
            }
            set
            {
                if (width != value)
                    width = value;
            }
        }
        public double Height
        {
            get
            {
                if(height == 0)
                    height = cellHeight * rowCount;
                return height;
            }
            set
            {
                if (height != value)
                    height = value;
            }
        }

        public GridVisual()
        {
            horizontalSeparator = new Pen();
            horizontalSeparator.Brush = new SolidColorBrush(Colors.Gray);
            horizontalSeparator.Thickness = 1;
            horizontalSeparator.DashStyle = new DashStyle(new double[]{4,4}, 0);
            horizontalSeparator.Brush.Opacity = 0.5;
            Render();
        }

        public void SizeChanged(object sender, SizeChangedEventArgs e)
        {
            Render();
        }
        private void Render()
        {
            if(width == 0)
                width = cellWidth * columnCount;
            if(height == 0)
                height = cellHeight * rowCount;
            double ydot=0;
            double xdot=0;
            double verticalHalfPen = verticalLine.Thickness/2;
            double horizontalHalfPen = horizontalLine.Thickness / 2;

            GuidelineSet gs = new GuidelineSet();
            for (int i = 0; i < rowCount; i++)
            {
                ydot = (i + 1) * cellHeight;
                gs.GuidelinesY.Add(ydot+verticalHalfPen);
            }
            for (int i = 0; i < columnCount; i++)
            {
                xdot = (i + 1) * cellWidth;
                gs.GuidelinesX.Add(xdot + horizontalHalfPen);

            }
            using (DrawingContext dc = this.RenderOpen())
            {
                dc.PushGuidelineSet(gs);
                for (int i = 0; i < rowCount; i++)
                {
                    ydot = (i+1)*cellHeight+margin.Top;
                    dc.DrawLine(verticalLine, new Point(0, ydot), new Point(width, ydot));
                }
                for (int i = 0; i < columnCount; i++)
                {
                    xdot = i * cellWidth +margin.Left;
                    if(i>0)
                        dc.DrawLine(horizontalLine, new Point(xdot, 0), new Point(xdot, ydot));
                    for (int j = 1; j < 6; j++)
                    {
                        dc.DrawLine(horizontalSeparator, new Point(xdot+(j * cellWidth / 6), 0), new Point(xdot+(j * cellWidth) / 6, ydot));
                    }
                   
                }
                dc.DrawRectangle(Brushes.Transparent, new Pen(Brushes.Transparent, 1), new Rect(new Point(0, 0), new Point(width, height)));
                dc.Pop();
                dc.Close();
            }
        }
    }
    public class VisitVisual :Button
    {

        public VisitVisual()
            :base()
        {
            //child = new DrawingVisual();
            Click += new RoutedEventHandler(ClickHandler);
            MouseEnter += new MouseEventHandler(MouseEnterHandler);
            MouseLeave += new MouseEventHandler(MouseLeaveHandler);
            ToolTip = new ToolTip();
            
        }
        private JournalChart host;
        private DTCVisit owner;
        private Point startPoint;
        private Point endPoint;
        private Brush background= Brushes.Orange;
        private Pen border =  new Pen(Brushes.Red, 1);

        public JournalChart Host
        {
            get
            {
                return host;
            }
            set
            {
                if (host != value)
                {
                    host = value;
                    SetSize();
                }
            }
        }
        public DTCVisit Visit
        {
            get
            {
                return owner;
            }
            set
            {
                if (owner != value)
                {
                    owner = value;
                }
            }
        }
        public Point StartPoint
        {
            get
            {
                return startPoint;
            }
            set
            {
                if (startPoint != value)
                {
                    startPoint = value;
                }
            }
        }
        public Point EndPoint
        {
            get
            {
                return endPoint;
            }
            set
            {
                if(endPoint != value)
                {
                    endPoint = value;
                }
            }
        }

        
        private void ClickHandler(object sender, RoutedEventArgs e)
        {
            VisitPopup vp = new VisitPopup();
            vp.Owner = App.Current.MainWindow;
            vp.Visit = owner;
            vp.ShowDialog();
        }
        private void MouseEnterHandler(Object sender, MouseEventArgs e)
        {
            Host.VisitFocused = true; 
        }
        private void MouseLeaveHandler(Object sender, MouseEventArgs e)
        {
            Host.VisitFocused = false;
        }
        private void SetSize()
        {
            if (host == null)
                return;
            if (owner == null)
                return;
            Height = Host.CellHeight-3;
            if (startPoint == null)
                startPoint = new Point();
            startPoint.X = Host.TimeToPos((DateTime)owner.DateFrom);
            startPoint.Y = Host.DoctorToPos(owner.DTCDoctor)*host.CellHeight+2;
            if(endPoint == null)
                endPoint = new Point();
            if (endPoint == startPoint)
                return;
            endPoint.X = Host.TimeToPos((DateTime)owner.DateTo);
            endPoint.Y = startPoint.Y;
            Width = Math.Abs( endPoint.X - startPoint.X)-1;

        }

    }
    public class SelectionVisual : DrawingVisual
    {
        public SelectionVisual()
        {
            lineBrush = new Pen(Brushes.OrangeRed, 1);
            background = new SolidColorBrush(Colors.Orange);
            background.Opacity = 0.3;;
        }

        private int selectedRow=-1;
        private double pos=-1;
        private DateTime time;
        private double rowHeight=0;
        private double width=0;
        private double height=0;
        private JournalChart host;
        private Pen lineBrush;
        private Brush background;
        private bool noLabel = false;

        public int SelectedRow
        {
            get
            {
                return selectedRow;
            }
            set
            {
                if (selectedRow != value)
                {
                    selectedRow = value;
                }
            }
        }
        public DateTime Time
        {
            get
            {
                return time;
            }
            set
            {
                if (time != value)
                {
                    time = value;
                }
            }
        }
        public double Position
        {
            get
            {
                return pos;
            }
            set
            {
                if (pos != value)
                {
                    pos = value;
                }
            }
        }
        public double RowHeight
        {
            get
            {
                return rowHeight;
            }
            set
            {
                if (rowHeight != value)
                {
                    rowHeight = value;
                    Render();
                }
            }
        }
        public double Width
        {
            get
            {
                return width;
            }
            set
            {
                if (width != value)
                {
                    width = value;
                    Render();
                }
            }
        }
        public double Heigth
        {
            get
            {
                return height;
            }
            set
            {
                if (height != value)
                {
                    height = value;
                    Render();
                }
            }
        }
        public JournalChart Host
        {
            get
            {
                return host;
            }
            set
            {
                if (host != value)
                {
                    host = value;
                    SizeChanged();
                }
            }

        }
        public Pen LineBrush
        {
            get
            {
                return lineBrush;
            }
            set
            {
                if (lineBrush != value)
                {
                    lineBrush = value;
                    Render();
                }
            }
        }
        public Brush Background
        {
            get
            {
                return background;
            }
            set
            {
                if (background != value)
                {
                    background = value;
                    Render();
                }
            }
        }
        public bool NoLabel
        {
            get
            {
                return noLabel;
            }
            set
            {
                if (noLabel != value)
                {
                    noLabel = value;
                    Render();
                }
            }
        }

        public void SizeChanged()
        {
            if (host == null)
                return;
            rowHeight = host.CellHeight;
            width = host.ActualWidth;
            height = host.ActualHeight;
        }
        public void Render()
        {
            if (host == null)
                return;
            if (selectedRow == -1)
            {
                this.RenderOpen();
                return;
            }
            GuidelineSet gs = new GuidelineSet();
            double verticalHalfPen = lineBrush.Thickness / 2;
            double horizontalHalfPen = lineBrush.Thickness / 2;
            gs.GuidelinesX.Add(0 + horizontalHalfPen);
            gs.GuidelinesY.Add(selectedRow * rowHeight + verticalHalfPen);
            gs.GuidelinesY.Add((selectedRow+1) * rowHeight + verticalHalfPen);
            gs.GuidelinesX.Add(pos + horizontalHalfPen);
            time = host.PosToTime(pos);
            using (DrawingContext dc = this.RenderOpen())
            {
                dc.PushGuidelineSet(gs);
                dc.DrawRectangle(background, lineBrush, new Rect(new Point(0, selectedRow * rowHeight), new Point(width, (selectedRow + 1) * rowHeight)));
                dc.DrawLine(lineBrush, new Point(pos, selectedRow * rowHeight), new Point(pos, (selectedRow + 1) * rowHeight));
                dc.Pop();
                dc.Close();
            }
        }
    }
    public class TimeLabelVisual : DrawingVisual
    {
        public TimeLabelVisual()
        {
        }
        private FormattedText ft;
        private int textSize = 12;
        private Brush background = Brushes.White;
        private Pen border = new Pen(Brushes.Gray, 1);
        private JournalChart host;
        private bool visible = true;
        private double position = 0;
        private Point startPoint = new Point(0,0);
        private int selectedRow = 0;

        private void SetText()
        {
                if (host != null)
                {
                    ft = new FormattedText(host.PosToTime(position).ToString("t"), CultureInfo.GetCultureInfo("ru-RU"),
                    FlowDirection.LeftToRight,
                    new Typeface("Veranda"),
                    textSize, Brushes.Blue);
                }
                else ft = null;
        }
        public JournalChart Host
        {
            get
            {
                return host;
            }
            set
            {
                if (host != value)
                    host = value;
            }
        }
        public bool Visible
        {
            get
            {
                return visible;
            }
            set
            {
                if (visible != value)
                {
                    visible = value;
                    Render();
                }
            }
        }
        public double Position
        {
            get
            {
                return position;
            }
            set
            {
                if (position != value)
                {
                    position = value;
                }
            }
        }
        public int SelectedRow
        {
            get
            {
                return selectedRow;
            }
            set
            {
                if (selectedRow != value)
                {
                    selectedRow = value;
                }
            }
        }


        public void Render()
        {
            if (visible)
            {
                using (DrawingContext dc = RenderOpen())
                {
                    Point tp = SelectPoint();
                    dc.DrawRectangle(background, border, new Rect(new Point(tp.X - 4, tp.Y - 2), new Point(tp.X + ft.Width + 4, tp.Y + ft.Height + 2)));
                    dc.DrawText(ft, tp);
                    dc.Close();
                }
            }
            else RenderOpen().Close();


        }
        private Point SelectPoint()
        {
            double y;
            double x;
            if (selectedRow != 0)
            {
                y = selectedRow * Host.CellHeight - textSize;
            }
            else
            {
                if (host.RowCount == 1)
                    y = selectedRow * Host.CellHeight;
                else
                    y = (selectedRow + 1) *Host.CellHeight;
            }
            SetText();
            if (position > ft.Width + 10)
                x = position - ft.Width - 5;
            else
                x = position;
            return new Point(x, y);
        }
    }
    public class NewVisitVisual : DrawingVisual
    {
        public NewVisitVisual()
        {
            border = new Pen(Brushes.Blue, 1);
            background = new SolidColorBrush(Colors.BlueViolet);
            background.Opacity = 0.5;
        }

        private JournalChart host;
        private Point startPoint;
        private Point endPoint;
        private bool isDrawing;
        private Pen border;
        private Brush background;
        private double defaultLength = 20;
        private FormattedText startTime;
        private FormattedText endTime;
        private double fontSize=12;
        private Brush labelTextColor =  Brushes.Blue;

        public JournalChart Host
        {
            get
            {
                return host;
            }
            set
            {
                if (host != value)
                {
                    host = value;
                }
            }
        }
        public Point StartPoint
        {
            get
            {
                return startPoint;
            }
            set
            {
                if (startPoint != value)
                {
                    startPoint = value;
                    if (host != null)
                    {
                        endPoint.X = startPoint.X + defaultLength * host.MinuteLength;
                        endPoint.Y = startPoint.Y + host.CellHeight;
                    }
                    else
                        endPoint = startPoint;
                    startTime = null;
                    endTime = null;
                    if (isDrawing == false)
                        isDrawing = true;
                    Render();
                }
            }
        }
        public Point EndPoint
        {
            get
            {
                return endPoint;
            }
            set
            {
                if (endPoint != value)
                {
                    endPoint = value;
                    endTime = null;
                    Render();
                }
            }
        }
        public double EndsAt
        {
            get
            {
                return endPoint.X;
            }
            set
            {
                if (endPoint.X != value)
                {
                    endPoint.X = value;
                    endTime = null;
                    Render();
                }
            }
        }

        public bool IsDrawing
        {
            get
            {
                return isDrawing;
            }
            set
            {
                if (isDrawing != value)
                {
                    isDrawing = value;
                    if (value == false)
                    {
                        startPoint.X = startPoint.Y = 0;
                        endPoint.X = endPoint.Y = 0;
                    }
                }
                Render();
            }
        }
        public Pen Border
        {
            get
            {
                return border;
            }
            set
            {
                if (border != value)
                    border = value;
            }
        }
        public Brush Background
        {
            get
            {
                return background;
            }
            set
            {
                if (background != value)
                    background = value;
            }
        }
        public double DefaultLength
        {
            get
            {
                return defaultLength;
            }
            set
            {
                if (defaultLength != value)
                    defaultLength = value;
            }
        }
        public double FontSize
        {
            get
            {
                return fontSize;
            }
            set
            {
                if (fontSize != value)
                {
                    fontSize = value;
                    if (startTime != null || endTime != null)
                    {
                        startTime = null;
                        endTime = null;
                        Render();
                    }
                }
            }
        }
        public Brush LabelTextColor
        {
            get
            {
                return labelTextColor;
            }
            set
            {
                if (labelTextColor != value)
                {
                    labelTextColor = value;
                    if (startTime != null || endTime != null)
                    {
                        startTime = null;
                        endTime = null;
                        Render();
                    }
                }
            }
        }

        public FormattedText StartTime
        {
            get
            {
                if (host != null)
                {
                    if (startTime == null)
                        startTime = FormatString(startPoint.X);
                    return startTime;
                }
                else return null;
            }
        }
        public FormattedText EndTime
        {
            get
            {
                if (host != null)
                {
                    if (endTime == null)
                        endTime = FormatString(endPoint.X);
                    return endTime;
                }
                else return null;
            }
        }

        private FormattedText FormatString(double pointX)
        {
            if (host != null)
            {
                return new FormattedText(host.PosToTime(pointX).ToString("t"),
                    CultureInfo.GetCultureInfo("ru-RU"),
                    FlowDirection.LeftToRight,
                    new Typeface("Veranda"),
                    FontSize,
                    LabelTextColor);
            }
            else return null;
        }
        public void Render()
        {
            using (DrawingContext dc = this.RenderOpen())
            {
                if(!isDrawing)
                {
                    dc.Close();
                    return;
                }
                dc.DrawRectangle(background, border, new Rect(startPoint, endPoint));
                Point tp = SelectPoint(startPoint, StartTime);
                dc.DrawRectangle(Brushes.White, new Pen(Brushes.Gray, 1), new Rect(new Point(tp.X - 4, tp.Y - 2), new Point(tp.X + StartTime.Width + 4, tp.Y + StartTime.Height + 2)));
                dc.DrawText(StartTime, tp);
                tp = SelectPoint(new Point(endPoint.X, startPoint.Y), EndTime);
                dc.DrawRectangle(Brushes.White, new Pen(Brushes.Gray, 1), new Rect(new Point(tp.X - 4, tp.Y - 2), new Point(tp.X + EndTime.Width + 4, tp.Y + EndTime.Height + 2)));
                dc.DrawText(EndTime, tp);
                dc.Close();
            }
        }
        private Point SelectPoint(Point OriginalPoint, FormattedText ft)
        {
            double y;
            double x;
            if (OriginalPoint.Y >=host.CellHeight)
            {
                y = OriginalPoint.Y - fontSize;
            }
            else
            {
                if (host.RowCount == 1)
                    y = OriginalPoint.Y;
                else
                    y = OriginalPoint.Y+host.CellHeight;
            }
            if (OriginalPoint.X > ft.Width + 10)
                x = OriginalPoint.X - ft.Width - 5;
            else
                x = OriginalPoint.X;
            return new Point(x, y);
        }



       
    }
    #endregion

    #region Canvas
    public class Chart: Canvas
    { 
         static Chart()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(Chart), new FrameworkPropertyMetadata(typeof(Chart)));
        }

        private List<Visual> visuals = new List<Visual>();
        protected override int VisualChildrenCount
        {
            get
            {
                return visuals.Count+Children.Count;
            }
        }

        public void ClearVisuals()
        {
            foreach (Visual vs in visuals)
            {
                base.RemoveLogicalChild(vs);
                base.RemoveVisualChild(vs);
            }
            visuals = new List<Visual>();
        }

        protected override Visual GetVisualChild(int index)
        {
            if (index == 0)
                return visuals[0];
            if (index == 1)
                return visuals[1];
            if (index == VisualChildrenCount - 1)
                return visuals[2];
            if (index == VisualChildrenCount - 2)
                return visuals[3];
            else return Children[index - 2];
        }

        public void AddVisual(Visual visual)
        {
            visuals.Add(visual);

            base.AddVisualChild(visual);
            base.AddLogicalChild(visual);
        }

        public void DeleteVisual(Visual visual)
        {
            visuals.Remove(visual);

            base.RemoveVisualChild(visual);
            base.RemoveLogicalChild(visual);
        }

        public DrawingVisual GetVisual(Point point)
        {
            HitTestResult hitResult = VisualTreeHelper.HitTest(this, point);
            return hitResult.VisualHit as DrawingVisual;
        }
        public void AddVisit(VisitVisual visit)
        {
            if (!Children.Contains(visit))
            {
                visit.SetValue(LeftProperty, visit.StartPoint.X);
                visit.SetValue(TopProperty, visit.StartPoint.Y);
                Children.Add(visit);
            }

        }
            

        public void AddGrid(GridVisual grid)
        {
            AddVisual(grid);
            hasGrid = true;
        }
        
        public void AddSelection(SelectionVisual sel)
        {
            AddVisual(sel);
            hasSelection = true;
        }
        public void AddTimeLable(TimeLabelVisual timel)
        {
            AddVisual(timel);
            hasTimeLable = true;
        }

        private bool hasGrid = false;
        public bool HasGrid
        {
            get
            {
                return hasGrid;
            }
        }
        private bool hasSelection = false;
        public bool HasSelection
        {
            get
            {
                return hasSelection;

            }
        }
        private bool hasTimeLable = false;
        public bool HasTimeLable
        {
            get
            {
                return hasTimeLable;
            }
        }
    }
    #endregion

        
}